/**
 ******************************************************************************
 * @file    drv_packer.c
 * @author  zpw
 * @version V1.0
 * @date
 * @brief   链路层通讯协议
 ******************************************************************************
 * @attention
 *          链路层通讯协议，数据封包解包
 *          起始符  仅数据长度（双字节小端）  数据          校验（全部异或）
 *          0x55    0x02 0x00              0x22  0x33    0xxx
 *
 ******************************************************************************
 */
#include "drv_packer.h"

#include "drv_server.h"

static uint8_t frame_decode(CMD_Packer *packer, uint8_t d);
static uint8_t frame_encode(CMD_Packer *packer, uint8_t *data, uint16_t size,
                            uint8_t type);

/**
 * @brief  使用动态内存时需要初始化
 * @note   size pack缓存的长度，大于最大的数据包长度就行,使用PACK_SIZE
 无rtos最好用静态内存,不然要改heap，common里面设置
 * @param  *cmd_packer:
 * @param  *handler:
 * @retval None
 */
void DRV_PackerInit(CMD_Packer *cmd_packer,
                    uint8_t (*handler)(uint8_t type, uint8_t *data,
                                       uint16_t len),
                    void (*send)(uint8_t *data, uint16_t size)) {
#if USE_DYNAMIC_MEM
  cmd_packer->packer = (uint8_t *)malloc(MAX_PACK_SIZE);
  if (!cmd_packer->packer) {
    printf("malloc failed\n");
  }
#endif

  cmd_packer->cb = handler;
  cmd_packer->send = send;
}

/**
 * @brief  解包输入数据
 * @note
 * @param  cmd_packer:
 * @param  *buff:
 * @param  size:
 * @retval None
 */
void DRV_Unpack(CMD_Packer *packer, uint8_t *buff, uint16_t size) {
  for (uint16_t i = 0; i < size; i++) {
    if (frame_decode(packer, buff[i]) == 1) {
      //解析成功,回调处理服务器消息
      packer->cb(packer->type, packer->packer, packer->flen);
    }
  }
}

/**
 * @brief  封包数据并发送
 * @note
 * @param  *packer:
 * @param  *buff:
 * @param  size:
 * @retval None
 */
void DRV_Pack(CMD_Packer *packer, uint8_t *buff, uint16_t size, uint8_t type) {
  frame_encode(packer, buff, size, type);
}

/**
 * @brief  数据解包
 * @note
 * @param  *packer:
 * @param  d:
 * @retval
 */
static uint8_t frame_decode(CMD_Packer *packer, uint8_t d) {
  if (packer->state == 0 && d == STX_L) {
    packer->state = 1;
    packer->test = 0x55;
  } else if (packer->state == 1) {
    packer->flen = d;
    packer->test ^= d;
    packer->state = 2;
  } else if (packer->state == 2) {
    packer->flen |= (uint16_t)d << 8;
    packer->test ^= d;
    //数据包超长得情况下直接丢包
    if (packer->flen > MAX_PACK_SIZE) {
      packer->state = 0;
    }
    packer->state = 3;
    packer->cnt = 0;
  } else if (packer->state == 3) {
    packer->check = d;
    packer->state = 4;
  } else if (packer->state == 4) {
    packer->test ^= d;
    packer->type = d;
    if (packer->flen) {
      packer->state = 5;
    } else {
      packer->state = 0;
    }
  } else if (packer->state == 5) {
    packer->packer[packer->cnt] = d;
    packer->test ^= d;
    packer->cnt++;

    if (packer->cnt == packer->flen) {
      packer->state = 0;
      if (packer->test == packer->check) {
        return 1;
      }
    }
  } else {
    packer->state = 0;
  }
  return 0;
}

static uint8_t frame_encode(CMD_Packer *packer, uint8_t *data, uint16_t size,
                            uint8_t type) {
#if USE_OS
  taskENTER_CRITICAL();
#endif
  static uint8_t tmp[8192];

  tmp[0] = 0x55;
  tmp[1] = size & 0xff;
  tmp[2] = (size >> 8) & 0xff;
  tmp[4] = type;
  tmp[3] = tmp[0] ^ tmp[1] ^ tmp[2] ^ tmp[4];
  for (int i = 0; i < size; i++) {
    tmp[3] ^= data[i];
  }

  //   memcpy(tmp + 5, data, size);

  if (packer->send == NULL) {
    printf("packer->send is null\n");
    return 0;
  }
  packer->send(tmp, 5);
  packer->send(data, size);
  
  printf("send size:%d\n", size + 5);

#if USE_OS
  taskEXIT_CRITICAL();
#endif

  return 1;
}
